%{
	#include <stdlib.h>
	#include <stdio.h>
	#include "ast.h"
	#include "syntax.tab.h"
	#include <string.h>
	
	int octal_to_decimal(const char *num);
	int hexadecimal_to_decimal(const char *num);
	int yycolumn = 1;
	#define YY_USER_ACTION yylloc.first_line = yylloc.last_line=yylineno; \
	yylloc.first_column = yycolumn; \
	yylloc.last_column = yycolumn + yyleng - 1; \
	yycolumn += yyleng;
%}

/* RE definitions */
%option	yylineno
delimiter	[ \t\r]
blank	{delimiter}+
letter	[a-zA-Z]
digit	[0-9]
decimal	[+\-]?(0|([1-9]{digit}*))
octal	[+\-]?((0[0-7])|0[1-7][0-7]+)
hexadecimal	[+\-]?(0[xX](([0-9abcdefABCDEF])|([1-9abcdefABCDEF][0-9abcdefABCDEF]+)))
temp	[0-9]+
float	[+\-]?({temp}\.{temp}?|{temp}?\.{temp})([eE][+\-]?{temp})?
id	({letter}|_)({letter}|{digit}|_)*
single_line_comment	\/\/.*
multiline_comment	\/\*(?:[^\*]|\*+[^\/\*])*\*+\/


/* rules */
%%
(\n\r)|(\n)	{yycolumn=1;}
{blank}	{}
{single_line_comment}	{}
{multiline_comment}	{}
{float}	{float x=atof(yytext); yylval.node_type=new_node_float("FLOAT", x); return FLOAT;}
{decimal}	{int x=atoi(yytext); yylval.node_type=new_node_int("INT", x); return INT;}
{octal}	{int x=octal_to_decimal(yytext); yylval.node_type=new_node_int("INT", x); return INT;}
{hexadecimal}	{int x=hexadecimal_to_decimal(yytext); yylval.node_type=new_node_int("INT", x); return INT;}
";"	{yylval.node_type=new_node_terminal("SEMI"); return SEMI;}
","	{yylval.node_type=new_node_terminal("COMMA"); return COMMA;}
"="	{yylval.node_type=new_node_terminal("ASSIGNOP"); return ASSIGNOP;}
"<"	{yylval.node_type=new_node_terminal("RELOP"); return RELOP;}
"<="	{yylval.node_type=new_node_terminal("RELOP"); return RELOP;}
"=="	{yylval.node_type=new_node_terminal("RELOP"); return RELOP;}
"!="	{yylval.node_type=new_node_terminal("RELOP"); return RELOP;}
">"	{yylval.node_type=new_node_terminal("RELOP"); return RELOP;}
">="	{yylval.node_type=new_node_terminal("RELOP"); return RELOP;}
"+"	{yylval.node_type=new_node_terminal("PLUS"); return PLUS;}
"-"	{yylval.node_type=new_node_terminal("MINUS"); return MINUS;}
"*"	{yylval.node_type=new_node_terminal("STAR"); return STAR;}
"/"	{yylval.node_type=new_node_terminal("DIV"); return DIV;}
"&&"	{yylval.node_type=new_node_terminal("AND"); return AND;}
"||"	{yylval.node_type=new_node_terminal("OR"); return OR;}
"."	{yylval.node_type=new_node_terminal("DOT"); return DOT;}
"!"	{yylval.node_type=new_node_terminal("NOT"); return NOT;}
"int"	{yylval.node_type=new_node_str("TYPE", "int");; return TYPE;}
"float"	{yylval.node_type=new_node_str("TYPE", "float"); return TYPE;}
"("	{yylval.node_type=new_node_terminal("LP"); return LP;}
")"	{yylval.node_type=new_node_terminal("RP"); return RP;}
"["	{yylval.node_type=new_node_terminal("LB"); return LB;}
"]"	{yylval.node_type=new_node_terminal("RB"); return RB;}
"{"	{yylval.node_type=new_node_terminal("LC"); return LC;}
"}"	{yylval.node_type=new_node_terminal("RC"); return RC;}
"struct"	{yylval.node_type=new_node_terminal("STRUCT"); return STRUCT;}
"return"	{yylval.node_type=new_node_terminal("RETURN"); return RETURN;}
"if"	{yylval.node_type=new_node_terminal("IF"); return IF;}
"else"	{yylval.node_type=new_node_terminal("ELSE"); return ELSE;}
"while"	{yylval.node_type=new_node_terminal("WHILE"); return WHILE;}
{id}	{char* dest = (char*)malloc(sizeof(char) * 50);strcpy(dest, yytext); yylval.node_type=new_node_str("ID", dest); return ID;}
.	{
  	printf("Error type A at Line %d: Mysterious characters \"%s\".\n", yylineno, yytext);
	my_is_error = 1;
	}
%%

int octal_to_decimal(const char *num) {
    int i = 0;
    int number = 0;
    int positive = 1;
    if (num[0] == '-') {
        positive = 0;
        i++;
    }
    if (num[0] == '+') {
        i++;
    }
    i++;
    while (num[i] != '\0') {
        number = number * 8 + (int) num[i] - 48;
        i++;
    }
    if (positive == 0) {
        return -number;
    } else {
        return number;
    }
}

int hexadecimal_to_decimal(const char *num) {
    int i = 0;
    int number = 0;
    int positive = 1;
    if (num[0] == '-') {
        positive = 0;
        i++;
    }
    if (num[0] == '+') {
        i++;
    }
    i+=2;
    while (num[i] != '\0') {
        if ((int) num[i] >= 48 && (int) num[i] <= 57) {
            number = number * 16 + (int) num[i] - 48;
        }
        if ((int) num[i] >= 65 && (int) num[i] <= 70) {
            number = number * 16 + (int) num[i] - 55;
        }
        if ((int) num[i] >= 97 && (int) num[i] <= 102) {
            number = number * 16 + (int) num[i] - 87;
        }
        i++;
    }
    if (positive == 0) {
        return -number;
    } else {
        return number;
    }
}
